/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  Descriptor as ComponentDescriptor,
  ViewBaseProps,
  ViewRawProps,
  ViewDescriptorWrapperBase,
  ColorValue,
  Color,
  RNInstance,
  Tag,
  RNComponentCommandReceiver,
  ViewPropsSelector,
} from '@rnoh/react-native-openharmony/ts';

export namespace GeometryTransitionView {
  export const NAME = 'GeometryTransitionView' as const;

  export interface DirectRawProps {
    geometryViewID: string;
    isFollow?: boolean;
    duration?: number;
    pageType: string;
  }

  export interface Props extends ViewBaseProps {}

  export interface State {}

  export interface RawProps extends ViewRawProps, DirectRawProps {}

  export class PropsSelector extends ViewPropsSelector<Props, RawProps> {
    get geometryViewID(): string {
      return this.rawProps.geometryViewID;
    }

    get isFollow(): boolean {
      return this.rawProps.isFollow ?? false;
    }

    get duration(): number {
      return this.rawProps.duration ?? 0;
    }

    get pageType(): string {
      return this.rawProps.pageType;
    }
  }

  export type Descriptor = ComponentDescriptor<typeof NAME, Props, State, RawProps>;

  export class DescriptorWrapper extends ViewDescriptorWrapperBase<typeof NAME, Props, State, RawProps, PropsSelector> {
    protected createPropsSelector(): PropsSelector {
      return new PropsSelector(this.descriptor.props, this.descriptor.rawProps);
    }
  }

  export interface EventPayloadByName {}

  export class EventEmitter {
    constructor(private rnInstance: RNInstance, private tag: Tag) {}

    emit<TEventName extends keyof EventPayloadByName>(eventName: TEventName, payload: EventPayloadByName[TEventName]): void {
      this.rnInstance.emitComponentEvent(this.tag, eventName, payload);
    }
  }

  export interface CommandArgvByName {}

  type CommandCallback<T extends keyof CommandArgvByName> = (argv: CommandArgvByName[T]) => void;

  export class CommandReceiver {
    private listenersByCommandName = new Map<string, Set<CommandCallback<keyof CommandArgvByName>>>();
    private cleanUp: (() => void) | undefined = undefined;

    constructor(private componentCommandReceiver: RNComponentCommandReceiver, private tag: Tag) {}

    subscribe<TCommandName extends keyof CommandArgvByName>(commandName: TCommandName, listener: CommandCallback<TCommandName>): () => void {
      if (!this.listenersByCommandName.has(commandName)) {
        this.listenersByCommandName.set(commandName, new Set());
      }
      this.listenersByCommandName.get(commandName)!.add(listener);
      const hasRegisteredCommandReceiver = !!this.cleanUp;
      if (!hasRegisteredCommandReceiver) {
        this.cleanUp = this.componentCommandReceiver.registerCommandCallback(this.tag, (commandName: string, argv: CommandArgvByName[TCommandName]) => {
          if (this.listenersByCommandName.has(commandName)) {
            const listeners = this.listenersByCommandName.get(commandName)!;
            listeners.forEach(listener => {
              listener(argv);
            });
          }
        });
      }

      return (): void => {
        this.listenersByCommandName.get(commandName)?.delete(listener);
        if (this.listenersByCommandName.get(commandName)?.size ?? 0 === 0) {
          this.listenersByCommandName.delete(commandName);
        }
        if (this.listenersByCommandName.size === 0) {
          this.cleanUp?.();
        }
      };
    }
  }
}
